/**
 * @file loopbus.h
 * @brief
 *
 * @author morris (a_morris@163.com)
 * @version v0.0.3
 * @date 2022-07-18
 *
 *
 * @htmlonly <span style="font-weight: bold">History</span> @endhtmlonly
 *
 * Version|Describe|Auther|Date|comment
 * ------|------|------|------|------
 * v0.0.1|create file|morris|2022-01-21|create file
 * v0.0.2|分批闪灯|morris|2022-06-08|分批闪灯
 * v0.0.3|修改主机向量表|morris|2022-06-08|1. 向量表
 *
 *
 * @copyright <h2><center>Copyright &copy; 2022 All Rights
 * Reserved.</center></h2>
 */
#ifndef __LOOPBUS_H__
#define __LOOPBUS_H__

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

    /**
     * @defgroup loopbusGroup loopbus
     *
     * @{
     *
     **/

    enum
    {
        LOOPBUS_MODE_SLAVE  = 0,
        LOOPBUS_MODE_MASTER = 1,
    };

    enum
    {
        LOOPBUS_DISABLE = 0,
        LOOPBUS_ENABLE  = !LOOPBUS_DISABLE,
    };

    /**
     * @brief loopbus handle pointer
     *
     */
    typedef void *loopbus_handle_t;

    /**
     * @brief loopbus event state id
     *
     */
    typedef enum
    {
        LOOPBUS_EVENT_START = 0, ///< start event
        LOOPBUS_EVENT_WAIT,      ///< waiting event
        LOOPBUS_EVENT_END,       ///< end event
        LOOPBUS_EVENT_EXIT,      ///< exit event

        LOOPBUS_EVENT_T1_SC,
        LOOPBUS_EVENT_T2_SC,
    } loopbus_event_t;

    typedef enum
    {
        LOOPBUS_PORT_24V,
        LOOPBUS_PORT_12V,
        LOOPBUS_PORT_0V,
        LOOPBUS_PORT_TX,
    } loopbus_port_t;

    typedef enum
    {
        LOOPBUS_STATE_OK             = 0,
        LOOPBUS_START_ERROR          = 0x91,
        LOOPBUS_SC_ERROR             = 0x92,
        LOOPBUS_CMD_START_ERROR      = 0xA1,
        LOOPBUS_CMD_END_ERROR        = 0xA2,
        LOOPBUS_CMD_DATA_START_ERROR = 0xB1,
        LOOPBUS_CMD_DATA_END_ERROR   = 0xB2,
        LOOPBUS_RET_DATA_START_ERROR = 0xC1,
        LOOPBUS_RET_DATA_END_ERROR   = 0xC2,
        LOOPBUS_CNT_ERROR            = 0xFC,
    } loopbus_error_state_t;

    /**
     * @defgroup loopbusDriveGroup loopbus drive
     * @brief    drive
     *
     * @{
     *
     **/

    /**
     * @brief loopbus error event callback function
     *
     * @param[in] handle loopbus handle pointer
     * @param[in] error_event  loopbus event
     * @param[in] ctx
     *
     */
    typedef void (*loopbus_error_interrupt_t)(loopbus_handle_t handle, int error_event, void *ctx);

    /**
     * @brief loopbus event callback function
     *
     * @param[in] handle loopbus handle pointer
     * @param[in] event  loopbus event
     *
     */
    typedef void (*loopbus_event_interrupt_t)(loopbus_handle_t handle, loopbus_event_t event);

    typedef void (*loopbus_isolation_proc_callback_t)(loopbus_handle_t handle);

    /**
     * @brief 解析器句柄
     *
     */
    typedef struct loopbus_adapter *loopbus_adapter_handle_t;

    enum
    {
        LOOPBUS_ISOLATION_START = 0,
        LOOPBUS_ISOLATION_GET_SHORTADDRESS_TEMP,
        LOOPBUS_ISOLATION_GET_SHORTADDRESS,
        LOOPBUS_ISOLATION_GET_STATE,
        LOOPBUS_ISOLATION_SET_ALLOFF,
        LOOPBUS_ISOLATION_SET_DRVOFF,
        LOOPBUS_ISOLATION_GET_DIR,
        LOOPBUS_ISOLATION_SET_DIR,
        LOOPBUS_ISOLATION_SET_DRVON,
        LOOPBUS_ISOLATION_TRY,
        LOOPBUS_ISOLATION_END,
    };
    typedef int (*loopbus_isolation_fsm_callback_t)(uint8_t event, uint8_t *data);

    /**
     * @brief waveform generator timer ctrl function callback
     *
     */
    struct tim
    {
        /**
         * @brief waveform generator timer initialization function
         *
         */
        void (*init)(void);
        /**
         * @brief waveform generator timer start function
         *
         */
        void (*start)(void);

        void (*pause)(void);

        void (*resume)(void);
        /**
         * @brief waveform generator timer stop function
         *
         */
        void (*stop)(void);
        /**
         * @brief waveform generator timer async function
         *
         */
        void (*async)(void);
    };

    /**
     * @brief return current adc ctrl function callback
     *
     */
    struct adc
    {
        /**
         * @brief return current adc initialization function
         *
         */
        void (*init)(void);

        /**
         * @brief return current adc start function
         *
         */
        void (*start)(void);
    };

    /**
     * @brief gpio ctrl function callback
     *
     */
    struct gpio
    {
        void (*init)(void);
        void (*deinit)(void);
        uint8_t (*set)(loopbus_port_t port);
        uint8_t (*reset)(loopbus_port_t port);
        uint8_t (*get)(loopbus_port_t port);
    };

    struct power
    {
        void (*lp_on)(void);
        void (*lp_off)(void);
        uint8_t (*lp_state)(void);

        void (*rt_on)(void);
        void (*rt_off)(void);
        uint8_t (*rt_state)(void);
    };

    /**
     * @brief config
     *
     */
    typedef struct
    {
        uint8_t    mode;
        uint8_t    isolation_enable;
        /**
         * @brief waveform generator timer ctrl function callback
         *
         */
        struct tim tim;

        /**
         * @brief return current adc ctrl function callback
         *
         */
        struct adc adc;

        /**
         * @brief gpio ctrl function callback
         *
         */
        struct gpio gpio;

        /**
         * @brief power and isolator ctrl function callback
         *
         */
        struct power power;

        /**
         * @brief loopbus number
         *
         */
        uint8_t number;

        /**
         * @brief loopbus timer cycle, unit: us, default=915us
         *
         */
        uint32_t cycle_time;

        /**
         * @brief adapter task handle
         *
         * @note  if it is NULL, use inside adapter
         *
         */
        loopbus_adapter_handle_t adapter_hanlde;

        /**
         * @brief loopbus error event interrupt callback
         *
         */
        loopbus_error_interrupt_t error_interrupt;

        /**
         * @brief 事件中断函数
         *
         * @param[in] ctx loopbus handle pointer
         * @param[in] event  loopbus event
         *
         */
        loopbus_event_interrupt_t event_interrupt;

        /**
         * @brief 隔离处理事件
         *
         */
        loopbus_isolation_proc_callback_t isolation_proc;
    } loopbus_cfg_t;

    /**
     * @} loopbusDriveGroup loopbus drive
     *
     **/

    /**
     * @defgroup loopbusInfoGroup loopbus info
     * @brief    info
     *
     * @{
     *
     **/

    /**
     * @brief 回路基本信息
     *
     */
    typedef struct
    {
        const uint8_t sn[6];   ///< 设备长地址
        uint8_t       type;    ///< 设备类型
        uint8_t       address; ///< 设备短地址
        uint8_t       trunk;   ///< 设备主干号
        uint8_t       branch;  ///< 设备分支号
        /**
         * @brief 分区信息
         *
         */
        struct
        {
            uint16_t type : 4;  ///< 区类型
            uint16_t id   : 12; ///< 区ID
        } ZM[8];

    } loopbus_info_t;

    /**
     * @} loopbusInfoGroup loopbus info
     *
     **/

    /**
     * @brief 回路事件注册配置
     *
     */
    typedef struct
    {
        uint8_t e;
        uint8_t cmd_data_len;
        uint8_t return_data_len;
        void   *ctx;
        /**
         * @brief 解析器事件回调
         *
         * @param[in] handle loopbus handle pointer
         * @param[in] cmd adapter event command
         * @param[in] data adapter event data
         */
        void (*event_callback)(loopbus_adapter_handle_t handle, uint8_t cmd, void *ctx);
    } loopbus_register_event_cfg_t;

    /**
     * @defgroup loopbusAdapterGroup loopbus adapter
     * @brief    adapter
     *
     * @{
     *
     **/

    typedef void *loopbus_adapter_event_fd_t;

    typedef enum
    {
        LOOPBUS_ADAPTER_EVENT_NULL      = 0,
        LOOPBUS_ADAPTER_EVENT_SET_PORT  = 1,
        LOOPBUS_ADAPTER_EVENT_SET_TSA   = 0x11,
        LOOPBUS_ADAPTER_EVENT_SET_SA    = 0x12,
        LOOPBUS_ADAPTER_EVENT_CLR_STATE = 0xA2,
        LOOPBUS_ADAPTER_EVENT_RESET     = 0xAC,
    } loopbus_adapter_event_id_t;

    typedef struct
    {
        loopbus_adapter_event_id_t event;
        uint8_t                    data_len;
        void                      *data;
    } loopbus_adapter_event_msg_t;

    /**
     * @brief 解析器配置器
     *
     */
    typedef struct
    {
        uint8_t                 *sn;                /**< 设备长地址 */
        volatile uint8_t        *shortAddress_temp; /**< 设备临时短地址 */
        volatile uint16_t       *sys_state;         /**< 设备状态 */
        // volatile uint8_t        *dev_clang;         /**< 设备信息改变标志位,
        //                                           当回路发送设置事件时自动置1, 需要手动清零 */
        volatile uint8_t        *port_state;  /**< 端口状态 */
        volatile uint8_t        *led_disable; /**< 指示灯屏蔽 */
        volatile loopbus_info_t *info;        /**< 设备信息 */
        volatile void           *func;        /**< 解析器解析函数 */
        volatile uint8_t         ping_ttl;    /**< 心跳生存时间 */

        const void *event_cfg_list_start;
        const void *event_cfg_list_end;

        /**
         * @brief 解析器事件回调
         *
         * @param[in] handle loopbus handle pointer
         * @param[in] cmd adapter event command
         * @param[in] event adapter event id
         * @param[in] ctx user context
         */
        void (*event)(loopbus_adapter_handle_t handle, uint8_t event);

        /**
         * @brief ping事件回调
         *
         */
        void (*ping_callback)(uint8_t ping);

        /**
         * @brief 供电端(隔离器)电源控制
         *
         * @param[in] on_off 0 关闭, xx 打开
         *
         */
        void (*isolator_ctrl)(uint8_t on_off);

        /**
         * @brief 复位指令， 保留
         *
         */
        void (*reset)(void);
    } loopbus_adapter_cfg_t;

    /**
     * @} loopbusAdapterGroup loopbus adapter
     *
     **/

    /**
     * @defgroup loopbusDevGroup loopbus dev
     * @brief    dev
     *
     * @{
     *
     **/

    /**
     * @brief 获取配置信息
     *
     */
    typedef struct
    {
        void    *vector;
        uint32_t si;

        /**
         * @brief 回路初始化
         *
         * @param[in] cfg loopbus cfg
         * @return loopbus handle pointer
         *
         */
        loopbus_handle_t (*init)(loopbus_cfg_t *cfg);

        /**
         * @brief 获取回路配置参数
         *
         * @param[in] handle loopbus handle pointer
         * @return loopbus cfg
         *
         */
        loopbus_cfg_t (*get_cfg)(loopbus_handle_t handle);

        /**
         * @brief 发送事件
         *
         * @param[in] handle loopbus handle pointer
         * @param[in] event event id
         *
         */
        void (*event_send)(loopbus_handle_t handle, loopbus_event_t event);

        /**
         * @brief 获取回路协议版本号
         *
         * @return version string address
         *
         */
        char *(*get_version)(void);

        /**
         * @brief 判断回路Busy状态
         *
         * @param[in] handle 回路句柄
         * @return int 回路状态
         * @retval 0 is idle, (!0) is busy
         *
         */
        int (*is_busy)(loopbus_handle_t handle);

        int (*get_state)(loopbus_handle_t handle);
        int (*set_state)(loopbus_handle_t handle, uint8_t data);
        int (*get_next_state)(loopbus_handle_t handle);
        int (*set_next_state)(loopbus_handle_t handle, uint8_t data);
        int (*get_error_state)(loopbus_handle_t handle);
        int (*set_cmd_id)(loopbus_handle_t handle, uint8_t cmd);
        int (*get_cmd_id)(loopbus_handle_t handle);

        /**
         * @brief 获取回路请求数据
         *
         * @param[in] handle 回路句柄
         * @param[out] data  需要获取的数据
         * @return int 获取的数据长度
         *
         */
        int (*get_request_data)(loopbus_handle_t handle, uint8_t **data);

        /**
         * @brief 设置回路请求数据
         *
         * @param[in] handle 回路句柄
         * @param[in] data  需要设置的数据
         * @param[in] size  需要设置的数据长度
         * @return int 实际设置的数据长度
         *
         */
        int (*set_request_data)(loopbus_handle_t handle, uint8_t *data, uint8_t size);

        /**
         * @brief 获取回路响应数据
         *
         * @param[in] handle 回路句柄
         * @param[out] data  需要获取的数据
         * @return int 获取的数据长度
         *
         */
        int (*get_response_data)(loopbus_handle_t handle, uint8_t **data);

        /**
         * @brief 设置回路响应数据
         *
         * @param[in] handle 回路句柄
         * @param[in] data  需要设置的数据
         * @param[in] size  需要设置的数据长度
         * @return int 实际设置的数据长度
         *
         */
        int (*set_response_data)(loopbus_handle_t handle, uint8_t *data, uint8_t size);

        /**
         * @brief 获取应答位
         *
         * @param[in] handle 回路句柄
         * @return int 应答位
         * @retval 0 is nack, 1 is ack
         *
         */
        int (*get_ack)(loopbus_handle_t handle);

        /**
         * @brief 设置应答位
         *
         * @param[in] handle 回路句柄
         * @param[in] int 应答位, 0 is nack, 1 is ack
         *
         */
        void (*set_ack)(loopbus_handle_t handle, uint8_t ack);

        void *r[14];

        /**
         * @brief 主机协议解析器
         *
         * @param[in] handle loopbus handle pointer
         *
         */
        void (*master_analyze)(loopbus_handle_t handle);

        /**
         * @brief 从机协议解析器
         *
         * @param[in] handle loopbus handle pointer
         *
         */
        void (*slave_analyze)(loopbus_handle_t handle);

        void (*slave_tick_handler)(void);

        void (*isolation_init)(loopbus_isolation_fsm_callback_t callback);

        void *r2[28];

        /**
         * @brief master union
         */
        union
        {
            /**
             * @brief master struct
             */
            struct
            {
                /**
                 * @brief 获取上一次有效电流
                 *
                 * @param[in] handle loopbus handle pointer
                 *
                 */
                uint32_t (*get_last_current)(loopbus_handle_t handle);

                /**
                 * @brief 获取通信电流
                 *
                 * @param[in] handle loopbus handle pointer
                 * @param[out] down Bottom current
                 * @param[out] up return ack & bottom current
                 *
                 */
                void (*get_current)(loopbus_handle_t handle, uint32_t *down, uint32_t *up);

                /**
                 * @brief adc 转换为电流值
                 *
                 * @param[in] value adc value
                 *
                 * @return current value, uint ua
                 *
                 */
                float (*adc_value_to_current)(uint32_t value);

                /**
                 * @brief 打开左端供电(LP)电源
                 *
                 * @param[in] handle loopbus handle pointer
                 */
                void (*lp_power_on)(loopbus_handle_t handle);

                /**
                 * @brief 关闭左端供电(LP)电源
                 *
                 * @param[in] handle loopbus handle pointer
                 */
                void (*lp_power_off)(loopbus_handle_t handle);

                /**
                 * @brief 左端供电(LP)状态
                 *
                 */
                uint8_t (*lp_power_state)(loopbus_handle_t handle);

                /**
                 * @brief 打开右端供电(RT)电源
                 *
                 * @param[in] handle loopbus handle pointer
                 */
                void (*rt_power_on)(loopbus_handle_t handle);

                /**
                 * @brief 关闭右端供电(RT)电源
                 *
                 * @param[in] handle loopbus handle pointer
                 */
                void (*rt_power_off)(loopbus_handle_t handle);

                /**
                 * @brief 右端供电(RT)状态
                 *
                 */
                uint8_t (*rt_power_state)(loopbus_handle_t handle);

                /**
                 * @brief master signal collect callback
                 *
                 * @param[in] handle loopbus handle pointer
                 *
                 */
                void (*master_collector)(loopbus_handle_t handle);

                /**
                 * @brief master adc collection callback
                 *
                 * @param[in] handle loopbus handle pointer
                 * @param[in] result current adc value
                 *
                 */
                void (*adc_callback)(loopbus_handle_t handle, uint32_t result);

                int (*master_through)(loopbus_handle_t handle, const uint8_t cmd, const uint8_t *send_data,
                                      const uint8_t send_data_len, uint8_t *recv_data, const uint8_t recv_data_len);

                /**
                 * @brief master signal collect callback
                 *
                 * @param[in] handle loopbus handle pointer
                 * @param[in] result current adc value
                 *
                 */
                int (*master_check_tsa)(loopbus_handle_t handle, uint8_t tsa);

                /**
                 * @brief master check msb bit is 1
                 *
                 */
                int (*master_check_msb_bit)(loopbus_handle_t handle);

                /**
                 * @brief
                 *
                 */
                int (*master_check_n_bit_high)(loopbus_handle_t handle, uint8_t bit);
                int (*master_check_n_bit_low)(loopbus_handle_t handle, uint8_t bit);
                int (*master_last_ack_set_address)(loopbus_handle_t handle, uint8_t address);

                int (*master_sa_set_topology)(loopbus_handle_t handle, const uint8_t address, const uint8_t trunk,
                                              const uint8_t branch);

                int (*master_tsa_set_sa)(loopbus_handle_t handle, uint8_t tsa, uint8_t sa);
                int (*master_get_sa_sn)(loopbus_handle_t handle, uint8_t sa, uint8_t *sn);
                int (*master_set_isolator)(loopbus_handle_t handle, uint8_t sa, uint8_t state);

                int (*master_reset_node)(loopbus_handle_t handle);

                int (*master_check_alarm)(loopbus_handle_t handle, uint8_t num);
                int (*master_get_alarm_addr)(loopbus_handle_t handle, uint8_t *data, uint8_t *data2);
                int (*master_get_sa_state)(loopbus_handle_t handle, uint8_t sa, uint8_t *state);
                int (*master_mask_sa_state)(loopbus_handle_t handle, uint8_t sa, uint8_t state);

                int (*master_set_port_state)(loopbus_handle_t handle, uint8_t sa, uint8_t state);

                int (*master_set_led_state)(loopbus_handle_t handle, uint8_t sa, uint8_t state);

                int (*master_ping)(loopbus_handle_t handle, uint8_t *data, uint8_t *data2);

                int (*master_get_analog_value)(loopbus_handle_t handle, uint8_t sa, uint8_t dn, uint16_t *data,
                                               uint8_t size);

                int (*master_set_config)(loopbus_handle_t handle, const uint8_t sa, const uint8_t *data,
                                         const uint8_t size);
            };
            void *master_vectors[64];
        };

        /**
         * @brief slave union
         */
        union
        {
            /**
             * @brief slave struct
             *
             */
            struct
            {
                loopbus_adapter_handle_t (*adapter_init)(loopbus_adapter_cfg_t cfg);
                int (*slave_start_scheduler)(void);
                int (*slave_async_scheduler)(void);
                void (*slave_stop_scheduler)(void);
                int (*slave_check_connect)(void);
                loopbus_handle_t (*slave_get_loopbus_handle)(loopbus_adapter_handle_t handle);
                int (*slave_register_event_id)(loopbus_adapter_handle_t handle, uint8_t cmd,
                                               loopbus_register_event_cfg_t cfg);

                int (*slave_get_rx_data)(loopbus_adapter_handle_t handle, uint8_t **data);
                int (*slave_set_tx_data)(loopbus_adapter_handle_t handle, uint8_t *data, uint8_t size);
                void (*slave_set_ack)(loopbus_adapter_handle_t handle, uint8_t ack);
                void (*slave_state_report)(const loopbus_adapter_handle_t handle);
                loopbus_adapter_event_id_t (*slave_adapter_new_event)(loopbus_handle_t             handle,
                                                                      loopbus_adapter_event_msg_t *msg);
                int (*slave_set_isolation)(int enable);
            };
            void *slave_vectors[64];
        };
    } loopbus_t;

#ifndef VECTORS_BASE_ADDRESSS
#error Set this define to your loopbus flash start address, #define VECTORS_BASE_ADDRESSS (your flash address)
#endif

#define LOOPBUS_VECTORS_BASE_ADDRESSS (VECTORS_BASE_ADDRESSS)

#define LOOPBUS_ROM_OFFSET(offset)    (*(uint32_t *) (LOOPBUS_VECTORS_BASE_ADDRESSS + ((offset) *4)))

/**
 * @brief loopbus vector table
 *
 */
#define LOOPBUS_VECTORS               ((loopbus_t *) LOOPBUS_VECTORS_BASE_ADDRESSS)

    /**
     * @} loopbusDevGroup loopbus dev
     *
     **/
    typedef struct
    {
        uint8_t                             cmd;
        const loopbus_register_event_cfg_t *cfg;
    } lp_event_cfg_list_t;

#define LP_SECTION(section)         __attribute__((used, __section__(".loopbus." section)))

#define LP_A_EVCFG_SECTION(section) LP_SECTION("adapter.event.cfg." section)

#define LOOPBUS_ADAPTER_EVENT_CFG_INIT_HANDLE(desc)                                                                    \
    __attribute__((used)) const lp_event_cfg_list_t lp_event_cfg_start LP_A_EVCFG_SECTION("0.end") = {0, 0};           \
    __attribute__((used)) const lp_event_cfg_list_t lp_event_cfg_end   LP_A_EVCFG_SECTION("1.end") = {0, 0};

#define LOOPBUS_ADAPTER_EVENT_CFG_HANDLE_EXTERN(desc)                                                                  \
    extern const lp_event_cfg_list_t lp_event_cfg_start;                                                               \
    extern const lp_event_cfg_list_t lp_event_cfg_end;

#define LOOPBUS_ADAPTER_EVENT_CFG_EXPORT(cmd, cfg, desc)                                                               \
     const lp_event_cfg_list_t lp_event_cfg_##cfg LP_A_EVCFG_SECTION("1") = {cmd, &cfg}

    /**
     * @} loopbusGroup loopbus
     *
     **/

#ifdef __cplusplus
}
#endif

#endif /* __LOOPBUS_H__ */
